package com.gitee.wsl.time.chinese

import com.gitee.wsl.time.chinese.bean.NineStar
import com.gitee.wsl.time.chinese.util.LunarUtil
import kotlin.math.abs


/**
 * 农历月
 *
 * @author 6tail
 */
class LunarMonth(
    /**
     * 农历年
     */
    val year: Int,
    /**
     * 农历月：1-12，闰月为负数，如闰2月为-2
     */
    val month: Int,
    /**
     * 天数，大月30天，小月29天
     */
    val dayCount: Int,
    /**
     * 初一的儒略日
     */
    val firstJulianDay: Double,
    val index: Int,
) {

    val zhiIndex: Int = (index - 1 + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12

    val isLeap: Boolean
        /**
         * 是否闰月
         *
         * @return true/false
         */
        get() = month < 0

    val ganIndex: Int
        get() {
            val offset: Int = (LunarYear.fromYear(year).ganIndex + 1) % 5 * 2
            return (index - 1 + offset) % 10
        }

    val gan: String
        get() = LunarUtil.GAN[this.ganIndex + 1]

    val zhi: String
        get() = LunarUtil.ZHI[zhiIndex + 1]

    val ganZhi: String
        get() = this.gan + this.zhi

    val positionXi: String
        get() = LunarUtil.POSITION_XI[this.ganIndex + 1]

    val positionXiDesc: String
        get() = LunarUtil.POSITION_DESC.get(this.positionXi)!!

    val positionYangGui: String
        get() = LunarUtil.POSITION_YANG_GUI[this.ganIndex + 1]

    val positionYangGuiDesc: String
        get() = LunarUtil.POSITION_DESC.get(this.positionYangGui)!!

    val positionYinGui: String
        get() = LunarUtil.POSITION_YIN_GUI[this.ganIndex + 1]

    val positionYinGuiDesc: String
        get() = LunarUtil.POSITION_DESC.get(this.positionYinGui)!!

    fun getPositionFu(sect: Int): String {
        return (if (1 == sect) LunarUtil.POSITION_FU else LunarUtil.POSITION_FU_2)[this.ganIndex + 1]
    }

    fun getPositionFuDesc(sect: Int): String {
        return LunarUtil.POSITION_DESC.get(getPositionFu(sect))!!
    }

    val positionCai: String
        get() = LunarUtil.POSITION_CAI[this.ganIndex + 1]

    val positionCaiDesc: String
        get() = LunarUtil.POSITION_DESC.get(this.positionCai)!!

    val positionTaiSui: String
        /**
         * 获取太岁方位
         *
         * @return 方位，如艮
         */
        get() {
            val p: String
            val m = abs(month) % 4
            when (m) {
                0 -> p = "巽"
                1 -> p = "艮"
                3 -> p = "坤"
                else -> p =
                    LunarUtil.POSITION_GAN[Solar.fromJulianDay(this.firstJulianDay).lunar.monthGanIndex]
            }
            return p
        }

    val positionTaiSuiDesc: String
        /**
         * 获取太岁方位描述
         *
         * @return 方位描述，如东北
         */
        get() = LunarUtil.POSITION_DESC.get(this.positionTaiSui)!!

    val nineStar: NineStar
        /**
         * 获取月九星
         *
         * @return 九星
         */
        get() {
            val index: Int = LunarYear.fromYear(year).zhiIndex % 3
            val m = abs(month)
            val monthZhiIndex = (13 + m) % 12
            var n = 27 - index * 3
            if (monthZhiIndex < LunarUtil.BASE_MONTH_ZHI_INDEX) {
                n -= 3
            }
            val offset = (n - monthZhiIndex) % 9
            return NineStar.fromIndex(offset)
        }

    override fun toString(): String {
        return year.toString() + "年" + (if (this.isLeap) "闰" else "") + LunarUtil.MONTH[abs(month)] + "月(" + dayCount + "天)"
    }

    /**
     * 获取往后推几个月的阴历月，如果要往前推，则月数用负数
     *
     * @param n 月数
     * @return 阴历月
     */
    fun next(n: Int): LunarMonth {
        if (0 == n) {
            return fromYm(year, month)
        } else if (n > 0) {
            var rest = n
            var ny = year
            var iy = ny
            var im = month
            var index = 0
            var months = LunarYear.fromYear(ny).months
            while (true) {
                val size: Int = months.size
                for (i in 0..<size) {
                    val m: LunarMonth = months.get(i)
                    if (m.year == iy && m.month == im) {
                        index = i
                        break
                    }
                }
                val more = size - index - 1
                if (rest < more) {
                    break
                }
                rest -= more
                val lastMonth: LunarMonth = months.get(size - 1)!!
                iy = lastMonth.year
                im = lastMonth.month
                ny++
                months = LunarYear.fromYear(ny).months
            }
            return months.get(index + rest)!!
        } else {
            var rest = -n
            var ny = year
            var iy = ny
            var im = month
            var index = 0
            var months = LunarYear.fromYear(ny)!!.months
            while (true) {
                val size: Int = months.size
                for (i in 0..<size) {
                    val m: LunarMonth = months.get(i)!!
                    if (m.year == iy && m.month == im) {
                        index = i
                        break
                    }
                }
                if (rest <= index) {
                    break
                }
                rest -= index
                val firstMonth: LunarMonth = months.get(0)
                iy = firstMonth.year
                im = firstMonth.month
                ny--
                months = LunarYear.fromYear(ny).months
            }
            return months.get(index - rest)
        }
    }

    companion object {
        /**
         * 通过农历年月初始化
         *
         * @param lunarYear  农历年
         * @param lunarMonth 农历月：1-12，闰月为负数，如闰2月为-2
         * @return 农历月
         */
        fun fromYm(lunarYear: Int, lunarMonth: Int): LunarMonth {
            return LunarYear.fromYear(lunarYear).getMonth(lunarMonth)!!
        }
    }
}
